package com.prim.lock;

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;

public class KodyLock implements Lock {

    //有一个变量标记谁获得了锁 原子类型的引用 后面会详细讲解
//    public AtomicReference<Thread> owner = new AtomicReference<>();
    private Thread owner;

    private BlockingDeque<Thread> waites = new LinkedBlockingDeque<>();

    public static void main(String[] args) {
        KodyLock lock = new KodyLock();
    }

    /**
     * 尝试去强锁
     *
     * @return
     */
    @Override
    public boolean tryLock() {
        //如果当前的owner为null，锁没有被占用，就把当前线程引用付给owner
        if (owner == null) {
            owner = Thread.currentThread();
            return true;
        } else {
            return false;
        }
    }


    /**
     * 获得锁
     */
    @Override
    public void lock() {
//        if (!tryLock()){
//            //强锁失败 被占用 线程挂起 使用park
//            //wait 使用synchornized 不推荐使用
//            //suspend 被弃用了
//            LockSupport.park();
//            //被唤醒后 要再一次抢锁 但是这种递归方式不好
//            lock();
//        }
        //为什么递归不好 递归的问题出在哪里？ 在栈帧不断方法入栈 栈可能爆掉
        while (!tryLock()) {
            //如果没有抢到锁 挂起
            //将挂起的线程放进等待队列中
            waites.offer(Thread.currentThread());
            LockSupport.park();
            //被唤醒后 再次执行tryLock抢锁
        }
    }

    /**
     * 释放锁
     */
    @Override
    public void unlock() {
        //释放当前线程锁
        if (owner == Thread.currentThread()) {
            owner = null;
            //唤醒其他线程 为什么不唤醒所有线程？
            //
            LockSupport.unpark(waites.poll());
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }


    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }


    @Override
    public Condition newCondition() {
        return null;
    }
}
